package com.imedical.strategy;

import com.imedical.entity.RequestDetail;
import com.imedical.enums.CoreConstant;
import com.imedical.enums.SendRequestEnum;
import com.imedical.util.CommonRequestDataDealUtils;
import com.imedical.util.R;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 请求FTP服务
 * ftp://NAS:EDS_China@192.168.7.242/FileDBData/ARCHIVE/2018/05/31/12275644-2/50692/Report/20180531102802_50692_27650da6-aded-49a8-ba07-436651ca7ffd.pdf
 * ftp://192.168.7.107:2223/2020/12/28/51369210555383768/吕双_201126224_201228348_US.pdf
 *
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2022/1/19
 */
@Slf4j
@Service
public class SendFtpRequestStrategy implements SendRequestStrategy {

    @Override
    public Object sendRequest(RequestDetail requestDetail) {
        if (StrUtil.startWithIgnoreCase(requestDetail.getUrl(), SendRequestEnum.FTP.name()) && !StrUtil.containsIgnoreCase(requestDetail.getUrl(), "@")) {
            log.error(StrUtil.format("ftp路径错误,ftp = {}", requestDetail.getUrl()));
            R.makeImageAndResponse(StrUtil.format("ftp路径错误,ftp = {}", requestDetail.getUrl()));
            return null;
        }

        // 解析ftp地址
        String ip;
        int port;
        String username;
        String password;
        String ftpFilePath;
        // ftp://NAS:EDS_China@192.168.7.107:2223/2020/12/28/51369210555383768/201126224_201228348_US.pdf
        List<String> trim = StrUtil.splitTrim(requestDetail.getUrl(), "@");
        // trim.get(1) =  192.168.7.107:2223/2020/12/28/51369210555383768/201126224_201228348_US.pdf
        List<String> ipAndPort = StrUtil.splitTrim(trim.get(1), "/");
        // ipAndPort.get(0) = 192.168.7.107:2223
        List<String> trimIpPort = StrUtil.splitTrim(ipAndPort.get(0), ":");
        // /2020/12/28/51369210555383768/201126224_201228348_US.pdf
        ftpFilePath = StrUtil.removePrefix(trim.get(1), ipAndPort.get(0));
        ip = trimIpPort.get(0);
        if (trimIpPort.size() >= 2) {
            port = Integer.parseInt(trimIpPort.get(1));
        } else {
            port = 21;
        }
        // trim.get(0) = ftp://NAS:EDS_China
        List<String> trimUserPass = StrUtil.splitTrim(StrUtil.splitTrim(trim.get(0), "//").get(1), ":");
        if (trimUserPass.size() < 2) {
            log.error(StrUtil.format("ftp 链接中用户名或者密码不完整，{}", requestDetail.getUrl()));
            R.makeImageAndResponse(StrUtil.format("ftp 链接中用户名或者密码不完整，{}", requestDetail.getUrl()));
            return null;
        }
        username = trimUserPass.get(0);
        password = trimUserPass.get(1);

        String fileName = FileUtil.getName(ftpFilePath);
        String downloadFilePath = CoreConstant.TMP_FILE_DIR + fileName;
        log.info("FTP的配置参数为：IP: 【{}】, PORT: 【{}】, USER: 【{}】, PASS: 【{}】, ftpPath: 【{}】, FileName: 【{}】", ip, port, username, password, ftpFilePath, fileName);

        // 构建FTP，下载PDF文件流
        buildFtpAndDownload(ip, port, username, password, ftpFilePath, fileName, downloadFilePath);

        if (!FileUtil.exist(downloadFilePath)) {
            log.error(StrUtil.format("FTP服务器上未找到对应的文件,{}", requestDetail.getUrl()));
            R.makeImageAndResponse(StrUtil.format("FTP服务器上未找到对应的文件,{}", requestDetail.getUrl()));
            return null;
        }
        // 处理下载的报告
        return CommonRequestDataDealUtils.dealDownloadFile(requestDetail.getDisplayMode(), downloadFilePath);
    }

    private void buildFtpAndDownload(String ip, int port, String username, String password, String ftpFilePath, String fileName, String downloadFilePath) {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(ip, port);
            //下面三行代码必须要，而且不能改变编码格式，否则不能正确下载中文文件
            ftp.setControlEncoding("GBK");
            FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
            conf.setServerLanguageCode("zh");
            //如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
            boolean login = ftp.login(username, password);
            log.info(StrUtil.format("是否登陆成功: {}", login));
            reply = ftp.getReplyCode();
            boolean positiveCompletion = FTPReply.isPositiveCompletion(reply);
            log.info(StrUtil.format("登陆确认状态码: {}, 登陆确认状态: {}", reply, positiveCompletion));
            if (!positiveCompletion) {
                ftp.disconnect();
            }
            //转移到FTP服务器目录
            String ftpDir = StrUtil.removeSuffix(ftpFilePath, fileName);
            log.info("ftp的文件所在目录: " + ftpDir);
            ftp.changeWorkingDirectory(ftpDir);
            // 很重要，如果Linux搭建的ftp环境没有开启被动模式传输数据时，一般不会读取到指定文件夹内的文件名称,调用FTPClient.enterLocalPassiveMode();这个方法的意思就是每次数据连接之前，ftp client告诉ftp server开通一个端口来传输数据。为什么要这样做呢，因为ftp server可能每次开启不同的端口来传输数据，但是在linux上，由于安全限制，可能某些端口没有开启，所以就出现阻塞。
            ftp.enterLocalPassiveMode();
            FTPFile[] fs = ftp.listFiles(ftpFilePath);

            log.info("FTP目录下文件个数：【{}】", fs.length);

            for (FTPFile ff : fs) {
                // ftp://192.168.7.107:2223 /2020/12/28/51369210555383768/吕双_201126224_201228348_US.pdf
                if (StrUtil.equalsIgnoreCase(ff.getName(), fileName)) {
                    OutputStream is = new FileOutputStream(FileUtil.file(downloadFilePath));
                    //注意此处retrieveFile的第一个参数由GBK转为ISO-8859-1编码。否则下载后的文件内容为空。
                    //原因: FTP协议规定文件编码格式为ISO-8859-1
                    ftp.retrieveFile(new String(ff.getName().getBytes("GBK"), StandardCharsets.ISO_8859_1), is);
                    is.close();
                }
            }
            ftp.logout();
        } catch (IOException e) {
            log.error("FTP下载报告失败,详细信息为：{}", ExceptionUtil.stacktraceToString(e));
            R.makeImageAndResponse(StrUtil.format("FTP下载文件失败, 失败原因为: {}", e.getMessage()));
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
